use std::io;
use std::io::prelude::*;
use std::path::PathBuf;

#[allow(dead_code)]
pub fn grep(target: &str) -> io::Result<()> {
    let stdin = io::stdin();
    for line_result in stdin.lock().lines() {
        let line = line_result?;
        if line.contains(target) {
            println!("{}", line);
        }
    }
    Ok(())
}

#[allow(dead_code)]
fn grep_by<R>(target: &str, reader: R) -> io::Result<()>
where R: BufRead,
{
    for line_result in reader.lines() {
        let line = line_result?;
        if line.contains(target) {
            println!("{}", line);
        }
    }
    Ok(())
}

#[allow(dead_code)]
fn grep_by2<R>(target: &str, reader: R) -> io::Result<()>
where R: BufRead,
{
    let lines = reader.lines().collect::<io::Result<Vec<String>>>()?;
    for line in lines {
        if line.contains(target) {
            println!("{}", line);
        }
    }
    Ok(())
}

#[allow(dead_code)]
pub fn grep_main()->io::Result<()> {
    let mut args = std::env::args().skip(1);
    let target = match args.next() {
        Some(arg) => arg,
        None => {
            eprintln!("Usage: grep PATTERN FILE ...");
            std::process::exit(1);
        }
    };

    let files :Vec<PathBuf> = args.map(PathBuf::from).collect();
    if files.is_empty() {
        let stdin = io::stdin();
        grep_by(&target, stdin.lock())?;
    } else {
        for file in files {
            let file = std::fs::File::open(file)?;
            let reader = io::BufReader::new(file);
            grep_by2(&target, reader)?;
        }
    }
    Ok(())
}
